home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / DOCVIEW.PAK / DUMPVIEW.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  11.8 KB  |  494 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // (C) Copyright 1993, 1995 by Borland International, All Rights Reserved
  4. //
  5. //   Implements class TDumpView
  6. //----------------------------------------------------------------------------
  7. #include <owl/pch.h>
  8. #include <owl/docmanag.h>
  9. #include <owl/filedoc.h>
  10. #include <owl/listbox.h>
  11. #include <owl/inputdia.h>
  12. #include <owl/dc.h>
  13. #include "dumpview.rc"
  14.  
  15. #include "dumpview.h"
  16.  
  17. DIAG_DECLARE_GROUP(OwlDocView);        // General Doc/View diagnostic group
  18.  
  19. const int DisplayLines = 16;   // initial list box size
  20. const int ListBoxMax = 100;    // max number of lines stored in list box
  21. const int DataWidth = 8;       // number of data bytes per line
  22. const int AddrWidth = 2;       // number of bytes in address
  23. const int LineWidth = AddrWidth*2 + 1 + DataWidth*3 + DataWidth;
  24.  
  25. struct TDumpData {
  26.    long       Addr;
  27.    char       Old[DataWidth];
  28.    char       New[DataWidth];
  29.    int        Count;
  30.    TDumpData* Next;
  31. };
  32.  
  33. DEFINE_RESPONSE_TABLE1(TDumpView, TListBox)
  34.   EV_WM_KEYDOWN,
  35.   EV_COMMAND(CM_DUMPUNDO,    CmEditUndo),
  36.   EV_COMMAND(CM_DUMPEDIT,    CmEditItem),
  37.   EV_WM_PAINT,
  38.   EV_WM_LBUTTONDOWN,
  39.   EV_WM_LBUTTONDBLCLK,
  40.   EV_VN_DOCCLOSED,
  41.   EV_VN_ISWINDOW,
  42.   EV_VN_ISDIRTY,
  43.   EV_VN_COMMIT,
  44.   EV_VN_REVERT,
  45.   EV_NOTIFY_AT_CHILD(LBN_SELCHANGE, CmSelChange),
  46. END_RESPONSE_TABLE;
  47.  
  48. TDumpView::TDumpView(TDocument& doc, TWindow* parent)
  49.          : TView(doc), TListBox(parent, GetNextViewId(), 0,0,0,0)
  50. {
  51.   Init();
  52. //  Attr.Style &= ~(WS_BORDER | LBS_SORT);
  53.   Attr.Style &= ~(LBS_SORT);
  54.   Attr.Style |= LBS_DISABLENOSCROLL | LBS_NOINTEGRALHEIGHT;
  55.   Attr.AccelTable = IDA_DUMPVIEW;
  56.   SetViewMenu(new TMenuDescr(IDM_DUMPVIEW,0,1,0,0,0,1));
  57. }
  58.  
  59. void
  60. TDumpView::Init()
  61. {
  62.   Origin = 0;
  63.   UpdateMode = 0;
  64.   Changes = 0;
  65. }
  66.  
  67. bool
  68. TDumpView::VnDocClosed(int omode)
  69. {
  70.   if (UpdateMode == -1 || !(omode & ofWrite))  // make sure someone else's write
  71.     return false;
  72.  
  73.   int top = GetTopIndex();
  74.   int sel = GetSelIndex();
  75.   ClearList();
  76.   LoadData(top, sel);
  77.   return true;
  78. }
  79.  
  80. static char HexDigit(int i)
  81. {
  82.   char c = char((i & 15) + '0');
  83.   if (c > '9')
  84.     c += char('A' - ('9' + 1));
  85.   return c;
  86. }
  87.  
  88. void
  89. TDumpView::FormatLine(int line, TDumpData* data)
  90. {
  91.   char buf[LineWidth + 2];
  92.   int index;
  93.   char* pbuf;
  94.   char* pasc;
  95.   unsigned char chr;
  96.   long addr = data->Addr;
  97.  
  98.   for (index = AddrWidth*2; --index >= 0; addr >>= 4)
  99.     buf[index] = HexDigit((int)addr);
  100.   pbuf = buf + AddrWidth*2;
  101.   *pbuf++ = ' ';
  102.   pasc = pbuf + DataWidth*3;
  103.   for (index = 0; index < DataWidth; index++) {
  104.     if (index < data->Count) {
  105.       chr = data->New[index];
  106.       *pbuf++ = HexDigit(chr >> 4);
  107.       *pbuf++ = HexDigit(chr);
  108.       pasc[index] = char((chr >= 0x20 && chr < 0x7F) ? chr : 0x7F);
  109.     } else {
  110.       *pbuf++ = ' ';
  111.       *pbuf++ = ' ';
  112.       pasc[index] = ' ';
  113.     }
  114.     *pbuf++ = ' ';
  115.   }
  116.   pasc[DataWidth] = 0;  // null terminate buffer
  117.   InsertString(buf, line);
  118. }
  119.  
  120. static long GetAddr(int index)
  121. {
  122.    return index * DataWidth;
  123.    // need to add origin!
  124. }
  125.  
  126. static int GetIndex(long addr)
  127. {
  128.    return int(addr / DataWidth);
  129.    // need to subtract origin!
  130. }
  131.  
  132. bool
  133. TDumpView::LoadData(int top, int sel)
  134. {
  135.   TDumpData data;
  136.   istream* inStream;
  137.   int count;
  138.  
  139.   if ((inStream = Doc->InStream(ofRead | ofBinary)) == 0)
  140.     return false;
  141.  
  142.   for (count=0, data.Addr=0; count<ListBoxMax; count++,data.Addr+=DataWidth) {
  143.     inStream->read(data.New, DataWidth);
  144.     if ((data.Count = inStream->gcount()) == 0)
  145.       break;
  146.     FormatLine(-1, &data);
  147.     if (data.Count != DataWidth)
  148.       break;
  149.   }
  150.   SetTopIndex(top);
  151.   SetSelIndex(sel);
  152.   delete inStream;   // close file in case process switch
  153.   return true;
  154. }
  155.  
  156. bool
  157. TDumpView::Create()
  158. {
  159.   TRect rect;
  160.   LOGFONT fontinfo;
  161.   HGDIOBJ font = GetStockObject(SYSTEM_FIXED_FONT);
  162.   TListBox::Create();   // throws exception TXInvalidWindow
  163.   SendMessage(WM_SETFONT, (uint)font, 0L);
  164.   GetObject(font, sizeof(LOGFONT), &fontinfo);
  165.   CharWidth  = fontinfo.lfWidth;
  166.   CharHeight = fontinfo.lfHeight;
  167.   GetClientRect(rect);   // created with 0,0 size, .right is -scroll bar size
  168.   if (rect.right < 0) {  // if new view, else streaming in presized window
  169.     rect.right = LineWidth * CharWidth + (-rect.right+2) + CharWidth/2;
  170.     rect.bottom = CharHeight * DisplayLines;
  171.     MoveWindow(rect);
  172.   //if (!Parent->IsFlagSet(wfMainWindow))// prevent parent shrink if main window
  173.       Parent->SetFlag(wfShrinkToClient);
  174.   }
  175.   if (!Doc->GetDocPath())
  176.     return true;           // new file, no data to display
  177.  
  178.   if (!LoadData(0, 0))
  179.     NotOK();
  180.   return true;
  181. }
  182.  
  183. bool
  184. TDumpView::VnCommit(bool /*force*/)
  185. {
  186.   TDumpData* edit;
  187.   ostream* outStream;
  188.  
  189.   EndEditLine();
  190.   if (!Changes)
  191.     return true;
  192.   if ((outStream = Doc->OutStream(ofReadWrite | ofBinary)) == 0)
  193.     return false;
  194.   while ((edit = Changes) != 0) {
  195.     outStream->seekp(edit->Addr);
  196.     outStream->write(edit->New, edit->Count);
  197.     // test goodbit
  198.     Changes = Changes->Next;
  199.     delete edit;
  200.   }
  201.   UpdateMode = -1;         // to detect our own close notification
  202.   outStream->seekp(0,ios::end);
  203.   delete outStream;
  204.   return true;
  205. }
  206.  
  207. bool
  208. TDumpView::VnRevert(bool clear)
  209. {
  210.   EndEditLine();
  211.   KillChanges();
  212.   ClearList();
  213.   return (!clear && Doc->GetDocPath() != 0) ? LoadData(0, 0) : true;
  214. }
  215.  
  216. TDumpView::~TDumpView()
  217. {
  218.   KillChanges();
  219. }
  220.  
  221. bool
  222. TDumpView::NewEditLine(int line, int byte)
  223. {
  224.   istream* inStream;
  225.   TDumpData* edit;
  226.   TRect rect;
  227.   bool stat = true;
  228.   if (line < 0)
  229.     return false;
  230.   SetSelIndex(line);  // restore index in case changes
  231.   if (UpdateMode > 0) {
  232.     return false;
  233.   }
  234.   if ((inStream = Doc->InStream(ofRead | ofBinary)) == 0)
  235.     return false;
  236.   if ((edit = new TDumpData) == 0)
  237.     return false;
  238.   edit->Addr = GetAddr(line);
  239.   inStream->seekg(edit->Addr);
  240.   // test goodbit
  241.   inStream->read(edit->Old, DataWidth);
  242.   if ((edit->Count = inStream->gcount()) > 0) {
  243.     memcpy(edit->New, edit->Old, edit->Count);
  244.     UpdateMode = 1;
  245.     GetItemRect(line, rect);
  246.     InvalidateRect(rect);
  247.     edit->Next = Changes;
  248.     Changes = edit;
  249.     while (byte >= edit->Count)
  250.       byte--;
  251.     EditByte = byte;
  252.     EditLine = line;
  253.   }
  254.   else {
  255.     delete edit;
  256.     stat = false;
  257.   }
  258.   delete inStream;
  259.   return stat;
  260. }
  261.  
  262. bool
  263. TDumpView::VnIsDirty()
  264. {
  265.   return (Changes
  266.           && (Changes->Next
  267.               || memcmp(Changes->New, Changes->Old, Changes->Count) != 0));
  268. }
  269.  
  270. void
  271. TDumpView::EndEditLine()
  272. {
  273.   TDumpData* edit = Changes;
  274.   if (UpdateMode > 0) {
  275.     TRect rect;
  276.     GetItemRect(EditLine, rect);
  277.     InvalidateRect(rect);
  278.     if (memcmp(edit->New, edit->Old, edit->Count) == 0) {
  279.       Changes = Changes->Next;
  280.       delete edit;
  281.     }
  282.   }
  283.   UpdateMode = 0;
  284. }
  285.  
  286. void
  287. TDumpView::KillChanges()
  288. {
  289.   TDumpData* edit;
  290.   while ((edit = Changes) != 0) {
  291.     Changes = Changes->Next;
  292.     delete edit;
  293.   }
  294. }
  295.  
  296. void
  297. TDumpView::EvLButtonDown(uint modKeys, TPoint& point)
  298. {
  299.   if (UpdateMode > 0) {
  300.     int line = point.y/CharHeight + GetTopIndex();
  301.     if (line != EditLine) {
  302.       EndEditLine();
  303.       TListBox::EvLButtonDown(modKeys, point);
  304.       return;
  305.     }
  306.  
  307.     int index = ((point.x*2 - CharWidth)/(CharWidth*2) - AddrWidth*2)/3;
  308.     if (index >= 0 && index < Changes->Count) {
  309.       EditByte = index;
  310.       UpdateMode = 1;
  311.       TRect rect;
  312.       GetItemRect(EditLine, rect);
  313.       InvalidateRect(rect);
  314.     }
  315.   } else
  316.     TListBox::EvLButtonDown(modKeys, point);
  317. }
  318.  
  319. void
  320. TDumpView::EvLButtonDblClk(uint /*modKeys*/, TPoint& point)
  321. {
  322.   int index = ((point.x*2 - CharWidth)/(CharWidth*2) - AddrWidth*2)/3;
  323.   if (index < 0 || index >= DataWidth)
  324.     index = 0;
  325.   int line = point.y/CharHeight + GetTopIndex();
  326.   if (UpdateMode <= 0 || line != EditLine) {
  327. //    EndEditLine();
  328.     NewEditLine(line, index);
  329.   }
  330. }
  331.  
  332. void
  333. TDumpView::EvKeyDown(uint key, uint repeatCount, uint flags)
  334. {
  335.   char oldchr, newchr;
  336.   MSG msg;
  337.  
  338.   if (UpdateMode <= 0) {
  339.     if (key != VK_LEFT && key != VK_RIGHT)
  340.       TListBox::EvKeyDown(key, repeatCount, flags);
  341.     return;
  342.   }
  343.   switch (key) {
  344.     case VK_ESCAPE:  // abort changes to current line
  345.       CmEditUndo();
  346.       return;
  347.  
  348.     case VK_RETURN:  // enter changes for current line, not committed yet
  349.       EndEditLine();
  350.       break;
  351.  
  352.     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  353.       key += ('0' + 10) - 'A';  // fall through to digit cases
  354.     case '0': case '1': case '2': case '3': case '4':
  355.     case '5': case '6': case '7': case '8': case '9':
  356.       newchr = char(key - '0');
  357.       oldchr = Changes->New[EditByte];
  358.       ::PeekMessage(&msg, GetHandle(), WM_CHAR, WM_CHAR, PM_REMOVE);
  359.       switch(UpdateMode) {
  360.         case 1:
  361.           newchr = char((oldchr & 0x0F) + (newchr<<4));
  362.           break;
  363.         case 2:
  364.           newchr = char((oldchr & 0xF0) + newchr);
  365.           break;
  366.         default:
  367.           return;
  368.       }
  369.       Changes->New[EditByte] = newchr;
  370.       DeleteString(EditLine);
  371.       FormatLine(EditLine, Changes);
  372.       SetSelIndex(EditLine);
  373.       if (UpdateMode++ == 2 && EditByte < Changes->Count-1) {
  374.         EditByte++;
  375.         UpdateMode = 1;
  376.       }
  377.       break;
  378.     case VK_UP:
  379.     case VK_DOWN:
  380.     case VK_PRIOR:
  381.     case VK_NEXT:
  382.     case VK_END:
  383.     case VK_HOME:
  384.       if (UpdateMode > 0)
  385.         return;
  386.       break;
  387.     case VK_LEFT:
  388.       if (UpdateMode <= 0 || EditByte == 0)
  389.         return;
  390.       UpdateMode = 1;
  391.       EditByte--;
  392.       break;
  393.     case VK_RIGHT:
  394.       if (UpdateMode <= 0 || EditByte >= (Changes->Count-1))
  395.         return;
  396.       UpdateMode = 1;
  397.       EditByte++;
  398.       break;
  399.     default:
  400.       break;
  401.   }
  402.   TRect rect;
  403.   GetItemRect(EditLine, rect);
  404.   InvalidateRect(rect);
  405. }
  406.  
  407. void
  408. TDumpView::EvPaint()
  409. {
  410.   TRegion updateRgn;
  411.   GetUpdateRgn(updateRgn);
  412.  
  413.   DefaultProcessing();  // predefined listbox class will paint, don't call TWindow
  414.  
  415.   if (UpdateMode <= 0)
  416.     return;
  417.   if (GetSelIndex() != EditLine) {
  418.     //::MessageBeep(MB_ICONEXCLAMATION);
  419.     return;
  420.   }
  421.   if (GetTopIndex() > EditLine || (GetTopIndex()+DisplayLines) <= EditLine)
  422.     return;
  423.  
  424.   TRect rect;
  425.   GetItemRect(EditLine, rect);
  426.   rect.left += CharWidth * (AddrWidth*2+1+EditByte*3) + 1;
  427.   rect.right = rect.left + CharWidth * 2;
  428.  
  429.   // should check if in update region!
  430.   TClientDC dc(GetHandle());
  431. //  dc.SelectClipRgn(updateRgn);
  432. //  dc.IntersectClipRect(rect);
  433. //  dc.InvertRgn(updateRgn);
  434.   dc.InvertRgn(updateRgn &= rect);
  435. }
  436.  
  437. void
  438. TDumpView::CmEditUndo()
  439. {
  440.   TRect rect;
  441.   TDumpData* edit;
  442.  
  443.   UpdateMode = 0;
  444.   if (!Changes)
  445.     return;
  446.   int index = GetIndex(Changes->Addr);
  447.   DeleteString(index);
  448.   memcpy(Changes->New, Changes->Old, Changes->Count);
  449.   FormatLine(index, Changes);
  450.   SetSelIndex(index);
  451.   edit = Changes;
  452.   Changes = Changes->Next;
  453.   delete edit;
  454.   GetItemRect(index, rect);
  455.   InvalidateRect(rect);
  456. }
  457.  
  458. void
  459. TDumpView::CmEditItem()
  460. {
  461.   int line = GetSelIndex();
  462.   if (UpdateMode > 0) {
  463.     if (line == EditLine)
  464.       return;
  465.     EndEditLine();
  466.   }
  467.   NewEditLine(line, 0);
  468. }
  469.  
  470. IMPLEMENT_STREAMABLE2(TDumpView, TListBox, TView);
  471.  
  472. void*
  473. TDumpView::Streamer::Read(ipstream& is, uint32 /*version*/) const
  474. {
  475.   ReadBaseObject((TListBox*)GetObject(), is);
  476.   ReadBaseObject((TView*)GetObject(), is);
  477.   is >> GetObject()->Origin;
  478.   GetObject()->Init();
  479.   return GetObject();
  480. }
  481.  
  482. void
  483. TDumpView::Streamer::Write(opstream &os) const
  484. {
  485.   WriteBaseObject((TListBox*)GetObject(), os);
  486.   WriteBaseObject((TView*)GetObject(), os);
  487.   os << GetObject()->Origin;
  488. }
  489.  
  490. DEFINE_DOC_TEMPLATE_CLASS(TFileDocument, TDumpView, DumpTemplate);
  491. DumpTemplate dumpTpl("DumpView, Binary files", "*.obj;*.res", 0, 0,
  492.                      dtAutoDelete | dtUpdateDir);
  493.  
  494.